package base

import (
	"fmt"
)

//基本类型
type Valuer interface {
	Value() []float64
	I(i int) float64
}

//基本元素的加法，减法等
//前提是A,B的数据不为nil也就是说在进行数据处理时要先进行数据监测
func Add(A, B Valuer) Valuer {

	var data = &Base{data: make([]float64, 0, len(A.Value()))}
	if len(A.Value()) != len(B.Value()) {
		panic("Add ")

	}
	for i := 0; i < len(A.Value()); i++ {
		data.data = append(data.data, A.I(i)+B.I(i))
	}
	if len(A.Value()) != len(data.data) {
		fmt.Println("A len is", len(A.Value()))
		fmt.Println("B len is", len(B.Value()))
		fmt.Println("Data len is", len(data.Value()))
		fmt.Println("Add")
	}
	return data
}
func Sub(A, B Valuer) Valuer {

	var data = &Base{data: make([]float64, 0, len(A.Value()))}
	if len(A.Value()) != len(B.Value()) {
		panic("Sub ")
	}
	for i := 0; i < len(A.Value()); i++ {
		data.data = append(data.data, A.I(i)-B.I(i))
	}
	if len(A.Value()) != len(data.data) || len(B.Value()) != len(data.data) {
		fmt.Println("A len is", len(A.Value()))
		fmt.Println("B len is", len(B.Value()))
		fmt.Println("Data len is", len(data.Value()))
		fmt.Println("Sub")
	}
	return data
}
func Mul(A, B Valuer) Valuer {

	var data = &Base{data: make([]float64, 0, len(A.Value()))}
	if len(A.Value()) != len(B.Value()) {
		panic("Mul ")
	}
	for i := 0; i < len(A.Value()); i++ {
		data.data = append(data.data, A.I(i)*B.I(i))
	}
	if len(A.Value()) != len(data.data) {
		fmt.Println("A len is", len(A.Value()))
		fmt.Println("B len is", len(B.Value()))
		fmt.Println("Data len is", len(data.Value()))
		fmt.Println("Mul")
	}
	return data
}
func MulWithNub(A Valuer, B int) Valuer {

	var data = &Base{data: make([]float64, 0, len(A.Value()))}
	for i := 0; i < len(A.Value()); i++ {
		data.data = append(data.data, A.I(i)*float64(B))
	}
	if len(A.Value()) != len(data.data) {
		fmt.Println(A.Value())
		panic("mul nub")
	}
	if len(A.Value()) != len(data.data) {
		fmt.Println("A len is", len(A.Value()))
		fmt.Println("Data len is", len(data.Value()))
		fmt.Println("MulWithNub")
	}
	return data
}

func Div(A, B Valuer) Valuer {

	var data = &Base{data: make([]float64, 0, len(A.Value()))}
	if len(A.Value()) != len(B.Value()) {
		fmt.Println(A.Value())
		fmt.Println(B.Value())

		panic("Div ")
	}
	for i := 0; i < len(A.Value()); i++ {
		if B.I(i) == 0 {
			data.data = append(data.data, 0)
			continue
		}
		data.data = append(data.data, A.I(i)/B.I(i))
	}
	if len(A.Value()) != len(data.data) {
		fmt.Println("A len is", len(A.Value()))
		fmt.Println("B len is", len(B.Value()))
		fmt.Println("Data len is", len(data.Value()))
		fmt.Println("Div")
	}
	return data
}
func DivWithNub(A Valuer, B int) Valuer {

	var data = &Base{data: make([]float64, 0, len(A.Value()))}

	for i := 0; i < len(A.Value()); i++ {
		data.data = append(data.data, A.I(i)/float64(B))
	}
	if len(A.Value()) != len(data.data) {
		fmt.Println("A len is", len(A.Value()))
		fmt.Println("Data len is", len(data.Value()))
		fmt.Println("DivWithNub")
	}
	return data
}

//基本类型
type Base struct {
	data []float64
}

func (b *Base) Value() []float64 {
	//fmt.Println("b.data:", b.data)
	return b.data
}
func (b *Base) Set(A []float64) {
	b.data = make([]float64, 0, len(A))
	for i := 0; i < len(A); i++ {
		b.data = append(b.data, A[i])
	}

}
func (b *Base) I(i int) float64 {

	return b.data[i]
}

/*含义：求指数平滑移动平均。
用法：EMA(X,N)，求X的N日指数平滑移动平均。算法：若Y=EMA(X,N)则Y=[2*X+(N-1)*Y']/(N+1)，其中Y'表示上一周期Y值。例如：EMA(CLOSE,30)表示求30日指数平滑均价。
*/
func EMA(A Valuer, B int) Valuer {
	if A.Value() == nil || len(A.Value()) <= 0 {
		fmt.Println("还有一个")
	}
	var data = &Base{data: make([]float64, 0, len(A.Value()))}

	Y := A.Value()[0]
	data.data = append(data.data, Y)
	for i := 1; i < len(A.Value()); i++ {

		Y = (2*A.I(i) + (float64(B)-1)*Y) / (float64(B) + 1)
		data.data = append(data.data, Y)
	}
	if len(A.Value()) != len(data.data) {
		fmt.Println("A len is", len(A.Value()))
		fmt.Println("Data len is", len(data.Value()))
		fmt.Println("EMA")
	}
	return data
}

/*含义：求移动平均。
用法：SMA(X,N,M)，求X的N日移动平均，M为权重。算法： 若Y=SMA(X,N,M)则 Y=[M*X+(N-M)*Y']/N,其中Y'表示上一周期Y值，N必须大于M。例如：SMA(CLOSE,30,1)表示求30日移动平均价。
*/
func SMA(A Valuer, B, C int) Valuer {
	if A.Value() == nil || len(A.Value()) <= 0 {
		fmt.Println("还有一个")
	}
	var data = &Base{data: make([]float64, 0, len(A.Value()))}

	Y := A.Value()[0]
	data.data = append(data.data, Y)
	for i := 1; i < len(A.Value()); i++ {

		Y = (float64(C)*A.I(i) + (float64(B)-float64(C))*Y) / float64(B)
		data.data = append(data.data, Y)
	}
	if len(A.Value()) != len(data.data) {
		fmt.Println("A len is", len(A.Value()))
		fmt.Println("Data len is", len(data.Value()))
		fmt.Println("SMA")
	}
	return data
}

func LLV(A Valuer, B int) Valuer {

	var data = &Base{data: make([]float64, 0, len(A.Value()))}

	for i := 0; i < len(A.Value()); i++ {
		var t int
		if i < B-1 {
			t = 0
		} else {
			t = i - B + 1
		}
		temp := A.Value()[t : i+1]
		var Lower float64 = temp[0]
		for j := 0; j < len(temp); j++ {
			if temp[j] < Lower {
				Lower = temp[j]
			}
		}
		data.data = append(data.data, Lower)
	}
	if len(A.Value()) != len(data.data) {

		fmt.Println("A len is", len(A.Value()))
		fmt.Println("A is", A.Value())
		fmt.Println("B is", B)
		fmt.Println("Data len is", len(data.Value()))
		fmt.Println("Data is", data.Value())
		fmt.Println("LLV")
	}
	return data
}
func HHV(A Valuer, B int) Valuer {

	var data = &Base{data: make([]float64, 0, len(A.Value()))}

	for i := 0; i < len(A.Value()); i++ {
		var t int
		if i < B-1 {
			t = 0
		} else {
			t = i - B + 1
		}
		temp := A.Value()[t : i+1]
		var Lower float64 = temp[0]
		for j := 0; j < len(temp); j++ {
			if temp[j] > Lower {
				Lower = temp[j]
			}
		}
		data.data = append(data.data, Lower)
	}
	if len(A.Value()) != len(data.data) {
		fmt.Println("A len is", len(A.Value()))
		fmt.Println("A is", A.Value())
		fmt.Println("B is", B)
		fmt.Println("Data len is", len(data.Value()))
		fmt.Println("Data  is", data.Value())
		fmt.Println("HHV")
	}
	return data
}
func REF(A Valuer, B int) Valuer {

	var data = &Base{data: make([]float64, 0, len(A.Value()))}

	var Newdata []float64
	for i := 0; i < B; i++ {
		Newdata = append(Newdata, A.Value()[0])
	}
	data.data = append(Newdata, A.Value()[0:len(A.Value())-B]...)
	if len(A.Value()) != len(data.data) {
		fmt.Println("A len is", len(A.Value()))
		fmt.Println("Data len is", len(data.Value()))
		fmt.Println("REF")
	}
	return data
}
